home *** CD-ROM | disk | FTP | other *** search
/ Aminet 40 / Aminet 40 (2000)(Schatztruhe)[!][Dec 2000].iso / Aminet / misc / emu / msh-156.lha / dev / device2.c < prev    next >
C/C++ Source or Header  |  1996-12-22  |  15KB  |  590 lines

  1. /*-
  2.  * $Id: device2.c,v 1.56 1996/12/21 23:34:35 Rhialto Rel $
  3.  * $Log: device2.c,v $
  4.  * Revision 1.56  1996/12/21  23:34:35  Rhialto
  5.  * Remove "register" from declarations,
  6.  * correct const funcTable.
  7.  *
  8.  * Revision 1.55  1993/12/30  22:45:10    Rhialto
  9.  * Remove InitTable.
  10.  * Do units 4..11.
  11.  * UnitCloseDown no longer gets the IO request.
  12.  *
  13.  * Revision 1.54  1993/06/24  04:56:00    Rhialto
  14.  * Switch to RTF_AUTOINIT, saves a few bytes. DICE 2.07.54R.
  15.  *
  16.  * Revision 1.53  92/10/25  02:10:25  Rhialto
  17.  * Add TD_Getgeometry, TD_Eject.
  18.  *
  19.  * Revision 1.52  92/09/06  00:04:07  Rhialto
  20.  * Include $VER in version string.
  21.  *
  22.  * Revision 1.51  92/04/17  15:41:55  Rhialto
  23.  * Freeze for MAXON3. Change cyl+side units to track units.
  24.  *
  25.  * Revision 1.46  91/10/06  18:22:08  Rhialto
  26.  * Freeze for MAXON; new syslog stuff
  27.  *
  28.  * Revision 1.42  91/06/13  23:45:09  Rhialto
  29.  * DICE conversion
  30.  *
  31.  * Revision 1.40  91/03/03  17:55:48  Rhialto
  32.  * Freeze for MAXON
  33.  *
  34.  * Revision 1.32  90/11/23  23:54:36  Rhialto
  35.  * Prepare for syslog
  36.  *
  37.  * Revision 1.30  90/06/04  23:18:39  Rhialto
  38.  * Release 1 Patch 3
  39.  *
  40.  * DEVICE.C
  41.  *
  42.  * The messydisk.device code that makes it a real Exec .device.
  43.  * Mostly based on the 1.1 RKM example and Matt Dillon's library code.
  44.  *
  45.  * This code is (C) Copyright 1989-1993 by Olaf Seibert. All rights reserved.
  46.  * May not be used or copied without a licence.
  47. -*/
  48.  
  49. #include <exec/initializers.h>
  50. #include "device.h"
  51.  
  52. /*#undef DEBUG            */
  53. #ifdef DEBUG
  54. #   include "syslog.h"
  55. #else
  56. #   define    debug(x)
  57. #endif
  58. /* INDENT ON */
  59.  
  60. Prototype __geta4 DEV *Init(__A0 long segment, __D0 struct MessyDevice *dev, __A6 struct ExecBase *execbase);
  61. Prototype __geta4 void DevOpen(__D0 ulong unitno, __D1 ulong flags, __A1 struct IOStdReq *ioreq, __A6 DEV *dev);
  62. Prototype __geta4 long DevClose(__A1 struct IOStdReq *ioreq, __A6 DEV *dev);
  63. Prototype __geta4 long DevExpunge(__A6 DEV *dev);
  64. Prototype __geta4 void DevBeginIO(__A1 struct IOStdReq *ioreq, __A6 DEV *dev);
  65. Prototype __geta4 long DevAbortIO(__A1 struct IOStdReq *ioreq, __A6 DEV *dev);
  66.  
  67. Prototype void TermIO(struct IOStdReq *ioreq);
  68. Prototype void WakePort(struct MsgPort *port);
  69. Prototype __geta4 void UnitTask(void);
  70. Prototype void CMD_Invalid(struct IOStdReq *ioreq, UNIT *unit);
  71. Prototype void CMD_Stop(struct IOStdReq *ioreq, UNIT *unit);
  72. Prototype void CMD_Start(struct IOStdReq *ioreq, UNIT *unit);
  73. Prototype void CMD_Flush(struct IOStdReq *ioreq, UNIT *unit);
  74. Prototype void TrackdiskGateway(struct IOStdReq *ioreq, UNIT *unit);
  75.  
  76. Prototype const char DevName[];
  77. Prototype const char idString[];
  78.  
  79. const char    DevName[] = "messydisk.device";
  80. const char    idString[] = "$\VER: messydisk.device $Revision: 1.56 $ $Date: 1996/12/21 23:34:35 $\r\n";
  81.  
  82. /*
  83.  * Device commands:
  84.  */
  85.  
  86. void           (*const funcTable[]) (struct IOStdReq *, UNIT *) = {
  87.     CMD_Invalid, CMD_Reset, CMD_Read, CMD_Write, CMD_Update, CMD_Clear,
  88.     CMD_Stop, CMD_Start, CMD_Flush, TD_Motor, TD_Seek, TD_Format,
  89.     TD_Remove, TD_Changenum, TD_Changestate, TD_Protstatus, TD_Rawread,
  90.     TD_Rawwrite, TD_Getdrivetype, TD_Getnumtracks, TD_Addchangeint,
  91.     TD_Remchangeint, TD_Getgeometry, TD_Eject,
  92. };
  93.  
  94. #define LAST_TD_COMM        TD_EJECT
  95.  
  96. long        SysBase;    /* Argh! A global variable! */
  97.  
  98. /*
  99.  * The Initialization routine is given a seglist pointer, the device
  100.  * base pointer, and the Exec base pointer. We are being called from
  101.  * InitResident. Exec has Forbid() for us during the call.
  102.  */
  103.  
  104.  
  105. __geta4 DEV    *
  106. Init(segment, dev, execbase)
  107. __A0 long    segment;
  108. __D0 DEV       *dev;
  109. __A6 struct ExecBase *execbase;
  110. {
  111.     SysBase = *(long *) 4;
  112. #ifdef DEBUG
  113.     initsyslog();
  114.     debug(("seg %lx, dev %lx, sys %lx\n", segment, dev, execbase));
  115. #endif
  116.     if (DevInit(dev)) {
  117.     dev->md_Seglist = segment;
  118.     debug(("init done.\n"));
  119.     return dev;
  120.     }
  121.     FreeMem((char *) dev - dev->dev_NegSize, dev->dev_NegSize + dev->dev_PosSize);
  122.     return NULL;
  123. }
  124.  
  125. /*
  126.  * Open is given the device pointer, unitno and flags.    Either return the
  127.  * device pointer or NULL.  Remove the DELAYED-EXPUNGE flag. Exec has
  128.  * Forbid() for us during the call.
  129.  */
  130.  
  131. __geta4 void
  132. DevOpen(unitno, flags, ioreq, dev)
  133. __D0 ulong    unitno;
  134. __D1 ulong    flags;
  135. __A1 struct IOStdReq *ioreq;
  136. __A6 DEV       *dev;
  137. {
  138.     UNIT       *unit;
  139.     int         nrflags;
  140.  
  141.     debug(("OpenDevice unit %ld, flags %lx\n", unitno, flags));
  142.     ++dev->dev_OpenCnt;
  143.  
  144.     if (nrflags = unitno / MD_NUMUNITS) {
  145.     /* Units 4..7 are fixed 40-tracks */
  146.     /* Units 8..11 are fixed non-40-tracks */
  147.     switch (nrflags) {
  148.     case 1:
  149.         flags |= IOMDF_40TRACKS | IOMDF_FIXFLAGS;
  150.         unitno -= MD_NUMUNITS;
  151.         break;
  152.     case 2:
  153.         flags &= ~IOMDF_40TRACKS;
  154.         flags |= IOMDF_FIXFLAGS;
  155.         unitno -= 2 * MD_NUMUNITS;
  156.         break;
  157.     }
  158.     }
  159.     if (unitno >= MD_NUMUNITS)
  160.     goto error;
  161.  
  162.     if ((unit = dev->md_Unit[unitno]) == NULL) {
  163.     if ((unit = UnitInit(dev, unitno, flags)) == NULL)
  164.         goto error;
  165.     dev->md_Unit[unitno] = unit;
  166.     }
  167.     ioreq->io_Unit = (struct Unit *) unit;
  168.  
  169.     ++unit->mu_OpenCnt;
  170.     dev->dev_Flags &= ~LIBF_DELEXP;
  171.     ioreq->io_Error = 0;
  172.     ioreq->io_Flags = flags;
  173.  
  174.     return;
  175.  
  176. error:
  177.     --dev->dev_OpenCnt;
  178.     ioreq->io_Error = IOERR_OPENFAIL;
  179. }
  180.  
  181. /*
  182.  * Close is given the device pointer and the io request.  Be sure not to
  183.  * decrement the open count if already zero.    If the open count is or
  184.  * becomes zero AND there is a LIBF_DELEXP, we expunge the device and
  185.  * return the seglist.    Otherwise we return NULL.
  186.  *
  187.  * Note that this routine never sets LIBF_DELEXP on its own.
  188.  *
  189.  * Exec has Forbid() for us during the call.
  190.  */
  191.  
  192. __geta4 long
  193. DevClose(ioreq, dev)
  194. __A1 struct IOStdReq *ioreq;
  195. __A6 DEV       *dev;
  196. {
  197.     UNIT       *unit;
  198.  
  199.     unit = (UNIT *) ioreq->io_Unit;
  200.     debug(("CloseDevice io %08lx unit %08lx\n", ioreq, unit));
  201.  
  202.     /*
  203.      * See if the unit is still in use. If not, close it down. This may
  204.      * need to do an update, which requires the ioreq.
  205.      */
  206.  
  207.     if (unit->mu_OpenCnt && --unit->mu_OpenCnt == 0) {
  208.     dev->md_Unit[unit->mu_UnitNr] = NULL;
  209.     UnitCloseDown(dev, unit);
  210.     }
  211.     /*
  212.      * Make sure the ioreq is not used again.
  213.      */
  214.     ioreq->io_Unit = (void *) -1;
  215.     ioreq->io_Device = (void *) -1;
  216.  
  217.     if (dev->dev_OpenCnt && --dev->dev_OpenCnt)
  218.     return NULL;
  219.     if (dev->dev_Flags & LIBF_DELEXP)
  220.     return DevExpunge(dev);
  221.     return NULL;
  222. }
  223.  
  224. /*
  225.  * We expunge the device and return the Seglist ONLY if the open count is
  226.  * zero. If the open count is not zero we set the DELAYED-EXPUNGE
  227.  * flag and return NULL.
  228.  *
  229.  * Exec has Forbid() for us during the call.  NOTE ALSO that Expunge might be
  230.  * called from the memory allocator and thus we CANNOT DO A Wait() or
  231.  * otherwise take a long time to complete (straight from RKM).
  232.  *
  233.  * Apparently RemLibrary(lib) calls our expunge routine and would therefore
  234.  * freeze if we called it ourselves.  As far as I can tell from RKM,
  235.  * DevExpunge(lib) must remove the device itself as shown below.
  236.  */
  237.  
  238. __geta4 long
  239. DevExpunge(dev)
  240. __A6 DEV       *dev;
  241. {
  242.     long        Seglist;
  243.  
  244.     if (dev->dev_OpenCnt) {
  245.     dev->dev_Flags |= LIBF_DELEXP;
  246.     return NULL;
  247.     }
  248.     Remove(&dev->dev_Node);
  249.     DevCloseDown(dev);          /* Should be quick! */
  250. #ifdef DEBUG
  251.     uninitsyslog();
  252. #endif
  253.     Seglist = dev->md_Seglist;
  254.     FreeMem((char *) dev - dev->dev_NegSize,
  255.         (long) dev->dev_NegSize + dev->dev_PosSize);
  256.     return Seglist;
  257. }
  258.  
  259. /*
  260.  * BeginIO entry point. We don't handle any QUICK requests, we just send
  261.  * the request to the proper unit to handle.
  262.  */
  263.  
  264. __geta4 void
  265. DevBeginIO(ioreq, dev)
  266. __A1 struct IOStdReq *ioreq;
  267. __A6 DEV       *dev;
  268. {
  269.     UNIT       *unit;
  270.  
  271.     /*
  272.      * Bookkeeping.
  273.      */
  274.     unit = (UNIT *) ioreq->io_Unit;
  275.     debug(("BeginIO: io %08lx dev %08lx u %08lx cmd %x\n", ioreq, dev, unit, ioreq->io_Command));
  276.  
  277.     /*
  278.      * See if the io command is within range.
  279.      */
  280.     if (STRIP(ioreq->io_Command) > LAST_TD_COMM)
  281.     goto NoCmd;
  282.  
  283. #ifdef HANDLE_IO_QUICK
  284.     Forbid();                   /* Disable(); is a bit too strong for us. */
  285. #endif
  286.  
  287.     /*
  288.      * Process all immediate commands no matter what. Don't even require
  289.      * an exclusive lock on the unit.
  290.      */
  291.     if (IMMEDIATE & (1L << STRIP(ioreq->io_Command)))
  292.     goto Immediate;
  293.  
  294.     /*
  295.      * We don't handle any QUICK I/O since that only gives trouble with
  296.      * message ports and so. Other devices normally would include the code
  297.      * below.
  298.      */
  299. #ifdef HANDLE_IO_QUICK
  300.     /*
  301.      * See if the user does not request QUICK IO. If not, it is likely to
  302.      * be async and therefore we don't do it sync.
  303.      */
  304.     if (!(ioreq->io_Flags & IOF_QUICK))
  305.     goto NoQuickRequested;
  306.  
  307.     /*
  308.      * See if the unit is STOPPED. If so, queue the msg.
  309.      */
  310.     if (unit->mu_Flags & UNITF_STOPPED)
  311.     goto QueueMsg;
  312.  
  313.     /*
  314.      * This is not an immediate command. See if the device is busy. If
  315.      * not, process the action in this (the caller's) context.
  316.      */
  317.     if (!BSET_ACTIVE(&unit->mu_Flags))
  318.     goto Immediate;
  319. #endif
  320.  
  321.     /*
  322.      * We need to queue the device. Clear the QUICK flag.
  323.      */
  324. QueueMsg:
  325.     ioreq->io_Flags &= ~IOF_QUICK;
  326. NoQuickRequested:
  327. #ifdef HANDLE_IO_QUICK
  328.     Permit();                   /* Enable(); is a bit too strong for us. */
  329. #endif
  330.     PutMsg(&unit->mu_Port, &ioreq->io_Message);
  331.  
  332.     return;
  333.  
  334. Immediate:
  335. #ifdef HANDLE_IO_QUICK
  336.     Permit();                   /* Enable(); is a bit too strong for us. */
  337. #endif
  338.     debug(("BeginIO: Immediate\n"));
  339.     ioreq->io_Error = TDERR_NoError;
  340.     PerformIO(ioreq, unit);
  341.     return;
  342.  
  343. NoCmd:
  344.     ioreq->io_Error = IOERR_NOCMD;
  345.     TermIO(ioreq);
  346.     return;
  347.  
  348. }
  349.  
  350. /*
  351.  * Terminate an io request. Called (normally) for every BeginIO. 'Funny'
  352.  * commands that don't call TermIO, or call it multiple times, may not be
  353.  * properly handled unless you are careful. TD_ADDCHANGEINT and
  354.  * TD_REMCHANGEINT are obvious examples.
  355.  */
  356.  
  357. void
  358. TermIO(ioreq)
  359. struct IOStdReq *ioreq;
  360. {
  361.     UNIT  *unit;
  362.  
  363.     unit = (UNIT *) ioreq->io_Unit;
  364.     debug(("TermIO: io %08lx u %08lx %ld %ld\n", ioreq, unit,
  365.        ioreq->io_Actual, (long)ioreq->io_Error));
  366.  
  367. #ifdef HANDLE_IO_QUICK
  368.     /*
  369.      * Since immediate commands don't even require an exclusive lock on
  370.      * the unit, don't unlock it.
  371.      */
  372.     if (IMMEDIATE & (1L << STRIP(ioreq->io_Command)))
  373.     goto Immediate;
  374.  
  375.     /*
  376.      * We may need to turn the active (lock) bit off, but not if we are
  377.      * within the task.
  378.      */
  379.     if (unit->mu_Flags & UNITF_INTASK)
  380.     goto Immediate;
  381.  
  382.     unit->mu_Flags &= ~UNITF_ACTIVE;
  383.  
  384.     /*
  385.      * The task may have work to do that came in while we were processing
  386.      * in the caller's context.
  387.      */
  388.     if (unit->mu_Flags & UNITF_WAKETASK) {
  389.     unit->mu_Flags &= ~UNITF_WAKETASK;
  390.     WakePort(&unit->mu_Port);
  391.     }
  392. #endif
  393.  
  394. Immediate:
  395.     /*
  396.      * If the quick bit is still set then wen don't need to reply the msg
  397.      * -- just return to the user.
  398.      */
  399.  
  400.     if (!(ioreq->io_Flags & IOF_QUICK))
  401.     ReplyMsg(&ioreq->io_Message);
  402.  
  403.     return;
  404. }
  405.  
  406. /*
  407.  * AbortIO entry point. We try to abort IO here.
  408.  */
  409.  
  410. __geta4 long
  411. DevAbortIO(ioreq, dev)
  412. __A1 struct IOStdReq *ioreq;
  413. __A6 DEV       *dev;
  414. {
  415.     Forbid();
  416.     if (ioreq->io_Flags & IOF_QUICK ||
  417.     IMMEDIATE & (1L << STRIP(ioreq->io_Command))) {
  418.     Permit();
  419.     return 1;
  420.     } else {
  421.     Remove(&ioreq->io_Message.mn_Node);
  422.     Permit();
  423.     ioreq->io_Error = IOERR_ABORTED;
  424.     ReplyMsg(&ioreq->io_Message);
  425.  
  426.     return 0;
  427.     }
  428. }
  429.  
  430. void
  431. WakePort(port)
  432. struct MsgPort *port;
  433. {
  434.     Signal(port->mp_SigTask, 1L << port->mp_SigBit);
  435. }
  436.  
  437. /*
  438.  * This is the main loop of the Unit tasks. It must be very careful with
  439.  * global data.
  440.  */
  441.  
  442. __geta4 void
  443. UnitTask()
  444. {
  445.     /* DEV *dev; */
  446.     UNIT       *unit;
  447.     long        waitmask;
  448.     struct IOExtTD *ioreq;
  449.  
  450.     {
  451.     struct Task    *task;
  452.  
  453.     task = FindTask(NULL);
  454.     unit = (UNIT *) task->tc_UserData;
  455.     /* dev = unit->mu_Dev; */
  456.     task->tc_UserData = NULL;
  457.     }
  458.  
  459.     /*
  460.      * Now finish initializing the message ports and other signal things
  461.      */
  462.  
  463.     {
  464.     byte        sigbit;
  465.  
  466.     unit->mu_DiskReplyPort.mp_SigBit = AllocSignal(-1L);
  467.     unit->mu_DiskReplyPort.mp_Flags = PA_SIGNAL;
  468.  
  469.     sigbit = AllocSignal(-1L);
  470.     unit->mu_Port.mp_SigBit = sigbit;
  471.     unit->mu_Port.mp_Flags = PA_SIGNAL;
  472.     waitmask = 1L << sigbit;
  473.  
  474.     unit->mu_DmaSignal = AllocSignal(-1L);
  475.     }
  476.  
  477.     for (;;) {
  478.     debug(("Task: Waiting...\n"));
  479.     Wait(waitmask);
  480.  
  481.     /*
  482.      * See if we are stopped.
  483.      */
  484.     if (unit->mu_Flags & UNITF_STOPPED)
  485.         continue;
  486.  
  487. #ifdef HANDLE_IO_QUICK
  488.     /*
  489.      * Lock the device. If it fails, we have set a flag such that the
  490.      * TermIO wakes us again.
  491.      */
  492.     unit->mu_Flags |= UNITF_WAKETASK;
  493.     if (BSET_ACTIVE(&unit->mu_Flags))
  494.         continue;
  495.  
  496.     unit->mu_Flags |= UNITF_INTASK;
  497. #endif
  498.  
  499.     while (ioreq = (struct IOExtTD *) GetMsg(&unit->mu_Port)) {
  500.         debug(("Task: io %08lx %lx\n", ioreq, (long)ioreq->iotd_Req.io_Command));
  501.         ioreq->iotd_Req.io_Error = 0;
  502.         PerformIO((&ioreq->iotd_Req), unit);
  503.     }
  504.  
  505. #ifdef HANDLE_IO_QUICK
  506.     unit->mu_Flags &= ~(UNITF_ACTIVE | UNITF_INTASK | UNITF_WAKETASK);
  507. #endif
  508.     }
  509. }
  510.  
  511. void
  512. CMD_Invalid(ioreq, unit)
  513. struct IOStdReq *ioreq;
  514. UNIT           *unit;
  515. {
  516.     ioreq->io_Error = IOERR_NOCMD;
  517.     TermIO(ioreq);
  518. }
  519.  
  520. void
  521. CMD_Stop(ioreq, unit)
  522. struct IOStdReq *ioreq;
  523. UNIT           *unit;
  524. {
  525.     unit->mu_Flags |= UNITF_STOPPED;
  526.     TermIO(ioreq);
  527. }
  528.  
  529. void
  530. CMD_Start(ioreq, unit)
  531. struct IOStdReq *ioreq;
  532. UNIT           *unit;
  533. {
  534.     unit->mu_Flags &= ~UNITF_STOPPED;
  535.     WakePort(&unit->mu_Port);
  536.     TermIO(ioreq);
  537. }
  538.  
  539. void
  540. CMD_Flush(ioreq, unit)
  541. struct IOStdReq *ioreq;
  542. UNIT           *unit;
  543. {
  544.     struct IOStdReq *req;
  545.  
  546.     /* Flush our own command queue */
  547.     Forbid();
  548.     while (req = (struct IOStdReq *) GetMsg(&unit->mu_Port)) {
  549.     req->io_Error = IOERR_ABORTED;
  550.     ReplyMsg(&req->io_Message);
  551.     }
  552.     Permit();
  553.  
  554.     WakePort(&unit->mu_Port);
  555.     TermIO(ioreq);
  556. }
  557.  
  558. void
  559. TrackdiskGateway(ioreq, unit)
  560. struct IOStdReq *ioreq;
  561. UNIT           *unit;
  562. {
  563.     struct IOExtTD *tdioreq;
  564.  
  565.     debug(("Trackdisk: %lx ", (long)ioreq->io_Command));
  566.     tdioreq = unit->mu_DiskIOReq;
  567.  
  568.     /*
  569.      * Clone almost the entire io request to relay to the
  570.      * trackdisk.device.
  571.      */
  572.  
  573.     tdioreq->iotd_Req.io_Command = ioreq->io_Command;
  574.     tdioreq->iotd_Req.io_Flags = ioreq->io_Flags | IOF_QUICK;
  575.     tdioreq->iotd_Req.io_Length = ioreq->io_Length;
  576.     tdioreq->iotd_Req.io_Data = ioreq->io_Data;
  577.     tdioreq->iotd_Req.io_Offset = ioreq->io_Offset;
  578.     if (ioreq->io_Command & TDF_EXTCOM) {
  579.     tdioreq->iotd_Count = ((struct IOExtTD *)ioreq)->iotd_Count;
  580.     tdioreq->iotd_SecLabel = ((struct IOExtTD *)ioreq)->iotd_SecLabel;
  581.     }
  582.     BeginIO((struct IORequest *)tdioreq);
  583.     WaitIO((struct IORequest *)tdioreq);
  584.  
  585.     ioreq->io_Error = tdioreq->iotd_Req.io_Error;
  586.     ioreq->io_Actual = tdioreq->iotd_Req.io_Actual;
  587.  
  588.     TermIO(ioreq);
  589. }
  590.